package com.smart.expand.config;

import com.smart.expand.bean.AnnotationMapping;
import com.smart.expand.bean.Constants;
import com.smart.expand.proxy.cglib.CglibDynamicProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Administrator
 */
public class BeanInitializeConfiguration implements BeanPostProcessor, ApplicationContextAware {

    private static final Logger log = LoggerFactory.getLogger(BeanInitializeConfiguration.class);

    private ApplicationContext applicationContext;
    private Map<String, AnnotationMapping> collect;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;

    }

    @PostConstruct
    private void init() {
        this.collect = Constants.annotationMappings.stream().collect(Collectors.toMap(annotationMapping -> annotationMapping.getAClass().getName(), annotationMapping -> annotationMapping));
        this.collect.putAll(Constants.annotationMappings.stream().filter(annotationMapping -> annotationMapping.getBeanName() != null).collect(Collectors.toMap(AnnotationMapping::getBeanName, annotationMapping -> annotationMapping)));
        log.info("== BeanInitializeConfiguration::postProcessAfterInitialization -> collect: {} ==", collect);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> targetClass = bean.getClass();
        if (this.collect.containsKey(targetClass.getName())) {
            AnnotationMapping annotationMapping = this.collect.get(targetClass.getName());
            log.info("== BeanInitializeConfiguration::postProcessAfterInitialization -> beanName: {} ==", beanName);
            if (annotationMapping.getMethodAnnotations().size() > 0){
                CglibDynamicProxy cglibDynamicProxy = CglibDynamicProxy.getInstance();
                Object newBean = targetClass.cast(cglibDynamicProxy.newProxyInstance(bean));
                for (Field declaredField : targetClass.getDeclaredFields()) {
                    declaredField.setAccessible(true);
                    try {
                        Object val = declaredField.get(bean);
                        declaredField.set(newBean, val);
                    } catch (IllegalAccessException e) {
                    }
                }
                bean = newBean;
            }
            annotationMapping.setBeanName(beanName);
        }
        return bean;
    }

}
